package com.tange.feature.device.query

import com.google.gson.Gson
import com.tange.core.backend.service.response.RxResponse
import com.tange.core.backend.service.response.RxResponseTransform
import com.tange.feature.data.structure.*
import com.tange.module.camera.query.DeviceCoreQuery
import com.tg.appcommon.android.TGLog
import com.tg.data.bean.DeviceItem
import com.tg.data.http.entity.*
import com.tg.network.socket.http.TGHttp
import io.reactivex.Observable
import io.reactivex.schedulers.Schedulers

/**
 * 完整查询业务层所需设备信息
 *
 * 依次请求，并合并所有嘻嘻：
 *    1. 设备基础信息 - /app/v1/device/list
 *    2. 设备套餐信息 - /app/v1/device/service
 *    3. 设备定位信息 - /app/v1/device/position
 *
 * 最后组装成 DeviceItem，回调给业务方。
 *
 * @author allenfeng
 */
object DeviceQuery {

    private const val TAG = "_DeviceQuery_"

    /** 请求单个设备的完整信息 */
    fun querySingleFull(
        deviceUuid: String
    ): Observable<RxResponse<DeviceItem?>> =
        queryMultipleFull(deviceUuid = deviceUuid).map { asBizDeviceRxResp(it, deviceUuid) }
        .subscribeOn(Schedulers.io()).observeOn(Schedulers.io())



    private fun queryMultipleFull(
        pageIndex: Int = 1,
        pageLimit: Int = 100,
        deviceNameFilter: String? = null,
        deviceUuid: String? = null
    ): Observable<RxResponse<DevicePaginationResp?>> =
        DeviceCoreQuery.queryDevicePagination(
            pageIndex,
            pageLimit,
            deviceNameFilter,
            deviceUuid
        ).map {

            val rxResponse = RxResponse<DeviceBasicPaginationResp?>()
            rxResponse.isSuccess = false

            if (!it.isSuccess || it.content == null) {
                rxResponse.errorMsg = it.errorMsg
                return@map rxResponse
            }

            try {
                val jsonObject = it.content ?: return@map rxResponse
                val resp = Gson().fromJson(
                    jsonObject.toString(),
                    DeviceBasicPaginationResp::class.java
                )
                rxResponse.content = resp
                rxResponse.isSuccess = true
                return@map rxResponse
            } catch (e: Exception) {
                rxResponse.errorMsg = e.toString()
                TGLog.i(TAG, "[queryDevicePagination] format error $e")
            }
            return@map rxResponse
        }.flatMap {
            queryAdditional(it)
        }

    private fun queryAdditional(_basicResponse: RxResponse<DeviceBasicPaginationResp?>): Observable<RxResponse<DevicePaginationResp?>> {
        val uuids = transformAsUuids(_basicResponse).also {
            TGLog.i(TAG, "[queryAdditional] uuids = $it")
        }

        return Observable.zip(
            DeviceAdditionalQuery.queryService(uuids),
            DeviceAdditionalQuery.queryLocation(uuids)
        ) { _serviceResp: RxResponse<HashMap<String, DeviceServiceStatusBean>>,
            _locationResp: RxResponse<HashMap<String, DeviceLocationResp>>
            ->
            zipAsFull(_basicResponse, _serviceResp, _locationResp)
        }.subscribeOn(Schedulers.io())
            .observeOn(Schedulers.io())
    }

    private fun zipAsFull(
        _basicPaginationResp: RxResponse<DeviceBasicPaginationResp?>,
        _serviceResp: RxResponse<HashMap<String, DeviceServiceStatusBean>>,
        _locationResp: RxResponse<HashMap<String, DeviceLocationResp>>
    ): RxResponse<DevicePaginationResp?> {

        TGLog.i(TAG, "[zipFull] _basicResp = $_basicPaginationResp")
        TGLog.i(TAG, "[zipFull] _serviceResp = $_serviceResp")
        TGLog.i(TAG, "[zipFull] _locationResp = $_locationResp")

        val rxResponse = RxResponse<DevicePaginationResp?>()
        rxResponse.isSuccess = false;

        if (!_basicPaginationResp.isSuccess) {
            rxResponse.errorMsg = _basicPaginationResp.errorMsg
            return rxResponse
        }

        if (!_serviceResp.isSuccess) {
            rxResponse.errorMsg = _serviceResp.errorMsg
            return rxResponse
        }

        if (!_locationResp.isSuccess) {
            rxResponse.errorMsg = _locationResp.errorMsg
            return rxResponse
        }

        val bizDevices = ArrayList<DeviceItem>()

        _basicPaginationResp?.content?.devices?.forEach { deviceBasic ->
            val bizDevice = convertBizDevice(deviceBasic)
            val uuid = bizDevice.uuid ?: ""
            _locationResp.content?.get(uuid)?.let { r -> applyLocation(bizDevice, r) }
            _serviceResp.content?.get(uuid)?.let { r -> applyService(bizDevice, r) }
            bizDevices.add(bizDevice)
        }

        val paginationResp = DevicePaginationResp().apply {
            total = _basicPaginationResp?.content?.total ?: 0
            devices = bizDevices
        }

        rxResponse.isSuccess = true
        rxResponse.content = paginationResp

        return rxResponse
    }

    private fun transformAsUuids(response: RxResponse<DeviceBasicPaginationResp?>): List<String> =
        ArrayList<String>().apply {
            response?.content?.devices?.forEach { response ->
                response.uuid?.let { add(it) }
            }
        }

    private fun asBizDeviceRxResp(
        it: RxResponse<DevicePaginationResp?>,
        deviceUuid: String
    ): RxResponse<DeviceItem?> {
        val rxResponse = RxResponse<DeviceItem?>()
        rxResponse.isSuccess = false
        if (it.isSuccess && it.content != null && (it.content?.devices?.size ?: 0) > 0) {
            val bizDevice = it.content?.devices?.get(0)

            bizDevice?.let { d ->
                if (deviceUuid == d.uuid) {
                    rxResponse.isSuccess = true
                    rxResponse.content = d
                } else {
                    rxResponse.isSuccess = false
                    rxResponse.errorMsg = "NOT SAME DEVICE RESPONSE"
                }
            }

        } else {
            rxResponse.errorMsg = it.errorMsg
            rxResponse.isSuccess = false
        }
        return rxResponse
    }
}